package com.shitou.shitoumember.config;

import com.alibaba.fastjson.JSON;
import com.shitou.shitoucommons.exception.RRException;
import com.shitou.shitoucommons.vo.MessageVo;
import com.shitou.shitoumember.service.MemberExchangeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * class detail:
 *
 * @author 石头人
 */
@SuppressWarnings("all")
@Slf4j
@Component
@ServerEndpoint("/shitou/room/{account}")
public class ChatRoom {



    private static MemberExchangeService exchangeService;

    @Autowired
    public void setExchangeService(MemberExchangeService exchangeService){
        ChatRoom.exchangeService = exchangeService;
    }


    private static AtomicInteger onlineNum = new AtomicInteger();

    //concurrent包的线程安全Set，用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    /**
     * 发送消息
     * @param session 会话
     * @param message 信息
     */
    public void sendMessage(Session session, String message){
        if ( session != null ){
            synchronized (session) {
//                log.info("发送的消息为: {}", message);
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException("发送消息时发生了IO异常");
                }
            }
        }
    }


    /**
     * 给单个用户发送消息
     * @param username 用户名，用以获取用户的session
     * @param message 待发送的消息
     */
    public void sendToSinglePerson(String account, String message){
        Session session = sessionPools.get(account);
        if ( session != null && !StringUtils.isEmpty(message) ){
            // 将消息添加到mysql中
            exchangeService.createExchange(JSON.parseObject(message, MessageVo.class));
            sendMessage(session, message);
//            log.info("给单个用户发送了在线消息,{}");

        }else {
            // 接收者处于离线状态，保存离线消息
            exchangeService.createOffLine(JSON.parseObject(message, MessageVo.class));
//            log.info("给单个用户发送了离线消息");
        }
//        log.info("您给{} 发送了消息", account);
    }


    /**
     * 群发消息
     * @param message 待发送的消息
     */
    public void broadcast(String message){
//        log.info("群发消息");
        if ( !StringUtils.isEmpty(message) ){
            for (Session session : sessionPools.values()) {
                if ( session != null ){
                    sendMessage(session, message);
                }
            }
        }
    }


    /**
     * 连接时自动调用
     * @param session 会话
     * @param account 用户账号
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "account") String account){

        Long id = null;
        try {
            id = Long.valueOf(account);
        } catch (NumberFormatException e){
            throw new RRException("用户账户信息错误");
        }

        // 将该用户的session加入到session池中
        sessionPools.put(account, session);
        onlineNum.set(sessionPools.size());   // 在线人数+1
//        log.info(account + "加入webSocket！当前人数为" + onlineNum);
        // TODO 告知所有订阅了该用户的会员该会员已经上线===前提是订阅的会员是在线的

        // 新会员用户上线，查找是否有离线消息
        List<MessageVo> offLineMessage = exchangeService.getOffLineMessage(id);
        if ( offLineMessage != null && offLineMessage.size() > 0 ){
            for (MessageVo messageVo : offLineMessage) {
                sendToSinglePerson(account, JSON.toJSONString(messageVo));
            }
        }
    }


    /**
     * 断开连接时调用
     * @param account
     */
    @OnClose
    public void onClose(@PathParam("account") String account){
        // 将该用户的会话从session池中移除
        sessionPools.remove(account);
        onlineNum.decrementAndGet();
        if ( sessionPools.size() == 0 ){
            onlineNum.set(0);
        }
//        log.info(account + "断开webSocket连接！当前人数为" + onlineNum);
    }


    /**
     * 有消息发送过来时，调用,如果发送者为-1，那么进行
     *  群发消息
     * @param message
     */
    @OnMessage
    public void onMessage(String message){
        MessageVo messageVo = JSON.parseObject(message, MessageVo.class);
//        log.info("server get Message is {}",messageVo.getText());
        if ( messageVo.getTo().equals("-1") ){
            broadcast(message);
        }else {
            sendToSinglePerson(messageVo.getTo(), message);
        }
    }


    /**
     * 错误时调用
     */
    @OnError
    public void onError(Session session, Throwable throwable){
//        log.error("发生错误");
        throwable.printStackTrace();
    }
}
